open Type
open Variable
open Lexer

(* print a boolean *)
let print_bool = function
      true -> "true"
	| _ -> "false"
;;

(* print abstract syntax tree *)
(*let rec display_ast = function
	  [] -> ""
	| head::tail -> match head with
					  Int(v) -> "Int("^(string_of_int v)^")"^(display_ast tail)
					| Float(v) -> "Float("^(string_of_float v)^")"^(display_ast tail)
					| Bool(v) -> "Bool("^(print_bool v)^")"^(display_ast tail)
					(*| Parenthesized(e) -> "Paren("^(display_ast [e])^")"^(display_ast tail) *)
					| Unary(op,e) -> "Binary(op, "^(display_ast [e])^")"^(display_ast tail)
					| Binary(e1, op, e2) -> "Binary("^(display_ast [e1])^", op,"^(display_ast [e2])^")"^(display_ast tail)
					| Assignment(var, e) -> "Assignement(var, "^(display_ast [e])^")"^(display_ast tail)
					| _ -> "todo"
;;
*)
(*
let display_expr = 
	  Int(v) -> "Int("^(string_of_int v)^")"
	| Float(v) -> "Float("^(string_of_float v)^")"
	| Bool(v) -> "Bool("^(print_bool v)^")"
	| Parenthesized(e) -> "Paren("^(display_ast_int [e])^")"
	| Unary(op,e) -> "Binary(op, "^(display_ast_int [e])^")"
	| Binary(e1, op, e2) -> "Binary("^(display_ast_int [e1])^", op,"^(display_ast_int [e2])^")"
	| Assignment(var, e) -> "Assignement(var, "^(display_ast_int [e])^")"
	| _ -> "todo"
;;
*)
let rec print_indent = function
	| x when x <= 0 -> ""
	| x -> " "^print_indent (x-1)
;;
(* print readable (?) ast *)

let rec display_ast_int lvl expr  =
	match expr with
	  Int(v) -> ("Int:"^(print_indent lvl)^(string_of_int v))
	| Float(v) -> (("Float :"^print_indent lvl)^(string_of_float v))	(*| Parenthesized(e) -> print_indent lvl ; print_string "()" ;
						display_ast_int lvl [e] ; display_ast_int lvl tail*)
	| Bool(v) -> ((print_indent lvl)^(print_bool v))
	| Unary(op,e) -> ((print_indent lvl)^op^"\n"^(display_ast_int lvl e))
	| Binary(Binary(e1, op1, e2), op2, Binary(e3, op3, e4)) -> ((print_indent (lvl))^op2^"\n"^
							(print_indent (lvl-2))^op1^"   "^op3^"\n"^(display_ast_int (lvl-3) e1)^(display_ast_int 1 e2)^
							(display_ast_int 1 e3)^(display_ast_int 1 e4))
	| Binary(Binary(e1, op1, e2), op2, e3) -> ((print_indent (lvl-1))^op2^(display_ast_int 1 e3)^"\n"^(display_ast_int (lvl-2) e1)^
				(display_ast_int 1 e2))
	| Binary(e1, op1, Binary(e2, o2, e3)) -> ((print_indent (lvl-1))^op1^(display_ast_int (lvl-2) e1)^"\n"^(display_ast_int (lvl-2) e2)^
				(display_ast_int 1 e3))	
	| Binary(e1, op, e2) -> ((print_indent lvl)^op^"\n"^(display_ast_int (lvl-1) e1)^
				(display_ast_int 1 e2))
	| Assignment(x, e) -> ((print_indent lvl)^(display_ast_int lvl x)^"\n"^(display_ast_int lvl e)^"\n")
	| Var(var) -> ("Var("^var^")")
	| Struct_If(if_list) -> "if_list"
	| TypedAssignment(_,_,_) -> "assign\n"
	| Print(_) -> "print"
	| Decl_Var(var) -> "decl"
	| _ -> "todo displ" 
;;

let display_ast2 ast = let test = List.map (display_ast_int 20) ast in List.iter print_string test ;;

(*
(* print an array *)
let rec print_array arr env =
	match arr with
	  [] -> print_string "[]"
	| [tail] -> print_intern [tail] env ; print_string "]"
	| head::tail -> print_intern [head] env ; print_string ", " ;
                  print_array tail env
  
(* print function *)
and print_intern expr env =
	match expr with
	  [] -> ()
	| head::tail -> begin match head with 
					  Bool(expr) -> print_bool expr
					| Int(expr) -> print_int expr
					| Float(expr) -> print_float expr
					| String(expr) -> print_string expr
					| Array(var) -> print_string "[" ; print_array var env
					| var -> (try let value = (get_var var env) in 
                   print_intern [value] env
							with NotFound -> failwith ("unknown variable :"))
					end ; 
	print_intern tail env
	
let print expr env = print_intern expr env ; print_newline ()
*)